/**
 * Form Validate & Check Module.
 */
define([
    'jquery'
], function ($) {
    (function ($, jQuery, window, undef) {
      $.extend({
        isString:function (source) {
            return '[object String]' === Object.prototype.toString.call(source);
        },
        formatString : function (source, opts) {
            source = String(source);
            var data = Array.prototype.slice.call(arguments, 1),
            toString = Object.prototype.toString;
            if (data.length) {
                data = data.length === 1 ?
                    /* ie 下 Object.prototype.toString.call(null) == '[object Object]' */
                    (opts !== null && (/\[object Array\]|\[object Object\]/.test(toString.call(opts))) ? opts : data)
                     : data;
                return source.replace(/#\{(.+?)\}/g, function (match, key) {
                    var replacer = data[key];
                    // chrome 下 typeof /a/ == 'function'
                    if ('[object Function]' === toString.call(replacer)) {
                        replacer = replacer(key);
                    }
                    return ('undefined' === typeof replacer ? '' : replacer);
                });
            }
            return source;
        }
      });
    })(jQuery, jQuery, window);
    (function ($, jQuery, window, undef) {
        // Define base object.
        // var root = this,
        // VAM = root.VAM = {};
        // VAM.uuid = '__VAM__SSP__';
        // VAM.lang = VAM.lang || {};
        // root[VAM.uuid] = root[VAM.uuid] || {};
        // (function () {
        //     var uuid = root[VAM.uuid];
        //     uuid._counter = uuid._counter || 1;
        //     VAM.lang.uuid = function () {
        //         return VAM.uuid + (uuid._counter++).toString(36);
        //     };
        // })();
        // root[VAM.uuid]._instances = root[VAM.uuid]._instances || {};
        // Define global language extends.
        VAM.lang.Class = function (uuid) {
            this.uuid - uuid || VAM.lang.uuid();
            window[VAM.uuid]._instances[this.uuid] = this;
        };
        VAM.lang.Class.prototype.dispose = function () {
        var property;
        delete window[SSP.uuid]._instances[this.uuid];

        for (property in this) {
            if (!$.isFunction(this[property])) {
                delete this[property];
            }
        }
        this.disposed = true;
        };
        VAM.lang.Class.prototype.toString = function () {
          return '[SSP object ' + (this._className || 'Object') + ']';
        };
        VAM.lang.Event = function (type, target) {
        this.type = type;
        this.returnValue = true;
        this.target = target || null;
        this.currentTarget = null;
        };
        VAM.lang.Class.prototype.addEventListener = function (type, handler, key) {
        if (!$.isFunction(handler)) {
            return;
        }
        !this.__listeners && (this.__listeners = {});

        var t = this.__listeners,
        id;
        if (typeof key === 'string' && key) {
            if (/[^\w\-]/.test(key)) {
                throw('nonstandard key:' + key);
            } else {
                handler.hashCode = key;
                id = key;
            }
        }
        type.indexOf('on') !== 0 && (type = 'on' + type);

        typeof t[type] !== 'object' && (t[type] = {});
        id = id || VAM.lang.uuid();
        handler.hashCode = id;
        t[type][id] = handler;
        };
        VAM.lang.Class.prototype.removeEventListener = function (type, handler) {
        if (typeof handler !== "undefined") {
            if (($.isFunction(handler) && !(handler = handler.hashCode))
                 || (!$.isString(handler))) {
                return;
            }
        }

        !this.__listeners && (this.__listeners = {});

        type.indexOf("on") !== 0 && (type = "on" + type);

        var t = this.__listeners,uuid;
        if (!t[type]) {
            return;
        }
        if (typeof handler !== "undefined") {
            t[type][handler] && delete t[type][handler];
        } else {
            for (uuid in t[type]) {
                delete t[type][uuid];
            }
        }
        };
        VAM.lang.Class.prototype.dispatchEvent = function (event, options) {
        var i,t,p;
        if ($.isString(event)) {
            event = new VAM.lang.Event(event);
        }
        !this.__listeners && (this.__listeners = {});

        // 20100603 添加本方法的第二个参数，将 options extend到event中去传递
        options = options || {};
        for (i in options) {
            if(options.hasOwnProperty(i)){
                event[i] = options[i];
            }
            
        }

        t = this.__listeners;
        p = event.type;
        event.target = event.target || this;
        event.currentTarget = this;

        p.indexOf("on") !== 0 && (p = "on" + p);

        $.isFunction(this[p]) && this[p].apply(this, arguments);

        if (typeof t[p] === "object") {
          for (i in t[p]) {
            if(t[p].hasOwnProperty(i)){
                t[p][i].apply(this, arguments);
            }
              
          }
        }
        return event.returnValue;
        };
        VAM.lang.createClass = function (constructor, options) {
            options = options || {};
            var superClass = options.superClass || VAM.lang.Class,
            fn = function () {
                if (superClass !== VAM.lang.Class) {
                    superClass.apply(this, arguments);
                } else {
                    superClass.call(this);
                }
                constructor.apply(this, arguments);
            },
            emptyClass, constructorPrototype, obj, i;
            fn.options = options.options || {};
            emptyClass = function () {};
            constructorPrototype = constructor.prototype;
            emptyClass.prototype = superClass.prototype;
            obj = fn.prototype = new emptyClass();
            for (i in constructorPrototype){
                if (constructorPrototype.hasOwnProperty(i)) {
                    obj[i] = constructorPrototype[i];
                }
            }
            typeof options.className === 'string' && (obj._className = options.className);
            obj.constructor = constructorPrototype.constructor;
            fn.extend = function (json) {
                var i;
                for (i in json) {
                    if (json.hasOwnProperty(i)) {
                        fn.prototype[i] = json[i];
                    }
                }
                return fn;
            };
            return fn;
        };
        VAM.object = VAM.object || {};

        VAM.extend = VAM.object.extend = function (target, source) {
        var p;
        for (p in source) {
            if (source.hasOwnProperty(p)) {
                target[p] = source[p];
            }
        }
        return target;
        };
        VAM.object.keys = function (source) {
        var result = [],
        resultLen = 0,
        k;
        for (k in source) {
            if (source.hasOwnProperty(k)) {
                result[resultLen++] = k;
            }
        }
        return result;
        };

        VAM.array = VAM.array || {};
        VAM.array.filter = function (source, iterator, thisObject) {
        var result = [],
        resultIndex = 0,
        len = source.length,
        item,
        i;

        if ('function' === typeof iterator) {
            for (i = 0; i < len; i++) {
                item = source[i];
                //TODO
                //和标准不符，see array.each
                if (true === iterator.call(thisObject || source, item, i)) {
                    // resultIndex用于优化对result.length的多次读取
                    result[resultIndex++] = item;
                }
            }
        }
        return result;
        };
        // Define global function extends.
        (function (VAM) {
            VAM.fn = VAM.fn || {};
            VAM.fn.blank = function () {};
            VAM.fn.bind = function (func, scope) {
                var xargs = arguments.length > 2 ? [].slice.call(arguments, 2) : null;
                return function () {
                    var fn = $.isString(func) ? scope[func] : func,
                    args = (xargs) ? xargs.concat([].slice.call(arguments, 0)) : arguments;
                    return fn.apply(scope || fn, args);
                };
            };

            $('body').ajaxError(function(e, jqxhr, settings, exception){
            var targetUrl = jqxhr.responseText;
            window.location = VAM.root + targetUrl;
            });
        })(VAM);
    })($, jQuery, window);
	(function($, jQuery, window, undef) {
    //START
    var CheckyRule,
        Checky;

    Checky = $.Checky = VAM.Checky = VAM.lang.createClass(function($form, fieldRule, options) {
        var me = this,
            fn = Checky,
            count = fn._addons.length,
            i = 0,
            eventNameList;
        me._form = $form.get(0);
        me._fieldRule = fieldRule;
        me._validRule = new CheckyRule();
        $.extend(me, options);
        eventNameList = me.validateEvent.split(',');

        //添加事件        
        function addEvent(eventName, key) {
            var entry = {
                $element: key ? $(me._form.elements[key]) : $form,
                eventName: eventName,
                handler: VAM.fn.bind('_onEventHandler', me, key)
            };
            entry.$element.bind(entry.eventName, entry.handler).bind('focus', function(e) {
                me.dispatchEvent('onfieldfocus', {
                    field: key,
                    event: e
                });
            });
            me.addEventListener('ondispose', function() {
                entry.$element.unbind(entry.eventName, entry.handler);
            });
        }
        $.each(me._fieldRule, function(key, value) {
            $.each($.isString(value.eventName) ? value.eventName.split(',') : eventNameList, function(i, item) {
                addEvent(item, key);
            });
        });
        me.validateOnSubmit && addEvent('submit');
        //插件机制
        for (i = 0; i < count; i++) {
            fn._addons[i](me);
        }
    }).extend({
        validateEvent: 'blur',
        validateOnSubmit: true,
        submitOnSucceed: true,
        _onEventHandler: function(key, evt) {
            var me = this;
            if (!key) { //如果是submit
                evt.preventDefault();
                me.validate(function(val, list) {
                    val && me.submitOnSucceed && me._form.submit();
                });
                return;
            }
            me.validateField(key);
        },

        /**
         * 添加一条规则到当前的验证器中
         * @param {String} name 规则名称
         * @param {Functioin|RegExp} handler 验证函数或是验证正则表达式，当是函数时需要在实现在显示返回一个boolean值
         * @param {Object|String} message 验证结果的提示信息，如：{success: 'success msg', failure: 'failure msg'}，当只有传入字符串时表示只有failure的提示
         */
        addRule: function(name, handler, message) {
            var me = this;
            me._validRule.addRule(name, handler);
            me.dispatchEvent('onaddrule', {
                name: name,
                handler: handler,
                message: message
            });
        },

        /**
         * 对所有表单进行验证，并把验证结果返回在callback函数中
         * @param {Function} callback 验证结束后的回调函数，第一参数表示验证结果，第二参数表示验证的失败项数组，各个项的json格式如：{type: 类型, field: 被验证域名称}
         */
        validate: function(callback) {
            var me = this,
                keyList = VAM.object.keys(me._fieldRule),
                resultList = [],
                count = 0;
            $.each(keyList, function(index, item) {
                me.validateField(item, function(val, list) {
                    resultList = resultList.concat(list);
                    if (count++ >= keyList.length - 1) {
                        $.isFunction(callback) && callback(resultList.length <= 0, resultList);
                        me.dispatchEvent('onvalidate', {
                            resultList: resultList
                        });
                    }
                });
            });
        },

        /**
         * 对单个验证域进行验证，结果返回在callback回调函数中
         * @param {String} name 单个验证域的名称
         * @param {Function} callback 验证结束后的回调函数，第一参数表示验证结果，第二参数表示验证的失败项数组，各个项的json格式如：{type: 类型, field: 被验证域名称}
         */
        validateField: function(name, callback) {
            var me = this,
                entry,
                rules = me._fieldRule[name].rule,
                //一定需要有rule
                value = me._form.elements[name].value,
                keyList = VAM.array.filter(VAM.object.keys(rules), function(item) { //过滤一些不需要的验证
                    entry = rules[item];
                    return (value || item === 'required') && (entry.hasOwnProperty('param') ? entry.param : entry) !== false;
                }),
                resultList = [],
                count = 0;

            function finish() { //当所有都验证完了以后
                if (count++ >= keyList.length - 1) {
                    me.dispatchEvent('validatefield', {
                        field: name,
                        resultList: resultList
                    });
                    $.isFunction(callback) && callback(resultList.length <= 0, resultList);
                }
            }
            keyList.length === 0 && finish(); //当keyList是空数组的时候表示没有需要验证的，则先提交
            $.each(keyList, function(index, item) {
                entry = rules[item];
                me._validRule.match(item, name, value, function(val) {
                    !val && resultList.push({
                        type: item,
                        field: name,
                        result: val
                    });
                    finish();
                }, {
                    param: entry.hasOwnProperty('param') ? entry.param : entry
                });
            });
        },

        /**
         * 析构函数
         */
        dispose: function() {
            var me = this;
            me.dispatchEvent('ondispose');
            VAM.lang.Class.prototype.dispose.call(me);
        }
    });
    Checky._addons = [];
    Checky.register = function(fn) {
        typeof fn === 'function' && Checky._addons.push(fn);
    };

    Checky.register(function(me) {
        if (!me.showMessage) {
            return;
        }
        me._defaultId = VAM.lang.uuid();
        me._defaultMessage = {
            required: 'This field is required.',
            remote: 'Please fix this field.',
            email: 'Please enter a valid email address.',
            number: 'Please enter a valid number.',
            maxlength: 'Please enter no more than #{param} characters.',
            minlength: 'Please enter at least #{param} characters.',
            rangelength: 'Please enter a value between #{param[0]} and #{param[1]} characters long.',
            equal: 'Please enter the same value again.',
            telephone: 'Please enter a valid telephone number.'
        };
        me.addEventListener('onaddrule', function(evt) {
            me._defaultMessage[evt.name] = evt.message;
        });

        me.addEventListener('onfieldfocus', function(evt) {
            var element = me._getContentElement(evt.field);
            if (!me._fieldRule[evt.field].focus) {
                return;
            }
            $(element).attr('class', '').addClass(['checky-', me.uiType, '-info'].join('')).
            addClass(['checky-', me.uiType, '-', evt.field, '-info'].join('')).html(me._fieldRule[evt.field].focus);
        });
        me.addEventListener('onvalidatefield', function(evt) {
            var element = me._getContentElement(evt.field),
                val = evt.resultList.length <= 0,
                key = val ? VAM.object.keys(me._fieldRule[evt.field].rule).pop() : evt.resultList[0].type,
                fieldRule = me._fieldRule[evt.field].rule[key],
                msg = fieldRule.message;
            !msg && (msg = me._defaultMessage[key]);
            msg = val ? (msg.success || '') : (msg.failure || msg);

            $(element).addClass(['checky-', me.uiType, '-', (val ? 'success' : 'failure')].join('')).
            addClass(['checky-', me.uiType, '-', evt.field, '-', (val ? 'success' : 'failure')].join('')).
            removeClass(['checky-', me.uiType, '-', (val ? 'failure' : 'success')].join('')).
            removeClass(['checky-', me.uiType, '-', evt.field, '-', (val ? 'failure' : 'success')].join('')).
            removeClass(['checky-', me.uiType, '-info'].join('')).
            removeClass(['checky-', me.uiType, '-', evt.field, '-info'].join(''));

            element.innerHTML = $.formatString(msg, { //这里扩展性不是很好啊
                param: fieldRule.param,
                'param[0]': $.isArray(fieldRule.param) ? fieldRule.param[0] : '',
                'param[1]': $.isArray(fieldRule.param) ? fieldRule.param[1] : ''
            });
        });
    });

    $.extend(Checky.prototype, {
        showMessage: true,
        uiType: 'default',
        tplDOM: '<em id="#{id}" class="#{class}"></em>',

        /**
         * 取得一个存放信息提示的容器，如果该容器不存在则创建一个容器
         * @param {String} field 验证域的名称
         * @return {HTMLElement} 返回一个DOM容器对象
         * @private
         */
        _getContentElement: function(field) {
            var me = this,
                rsid = [me._defaultId, '_', me.uiType, '_', field].join(''),
                element = $(['#', rsid].join('')).get(0),

                //修正me._fieldRule[field].messageContainer不存在的情况
                container = me._fieldRule[field].messageContainer ? $(['#', me._fieldRule[field].messageContainer].join('')) : me._fieldRule[field].messageContainer;
            if (!element) {
                container ? $(container).empty().append($.formatString(me.tplDOM, {
                    id: rsid,
                    'class': 'checky-' + me.uiType
                })) : $(me._form.elements[field]).after($.formatString(me.tplDOM, {
                    id: rsid,
                    'class': 'checky-' + me.uiType
                }));
                element = $(['#', rsid].join('')).get(0);
            }
            return element;
        },

        /**
         * 取得一个验证域对应的信息提示容器，如果该容器不存在返回空值
         * @param {String} field 验证域的name
         * @return {HTMLElement} 存放信息提示的容器
         */
        getMessageContainer: function(field) {
            return $(['#', this._defaultId + '_' + field].join(''));
        }
    });
    Checky.register(function(me) {
        if (!me.alertAnimate) {
            return;
        }
        me._defaultId = VAM.lang.uuid();
        me.addEventListener('onvalidatefield', function(evt) {

            var $element = $(me._form.elements[evt.field]),
                val = evt.resultList.length <= 0;

            !val ? $element.addClass(['checky-', me.animateClass].join('')) : $element.removeClass(['checky-', me.animateClass].join(''));
            return $element;
        });
    });
    $.extend(Checky.prototype, {
        alertAnimate: true,
        animateClass: 'input-error'
    });

    CheckyRule = $.CheckyRule = VAM.CheckyRule = VAM.lang.createClass(function() {
        var me = this;
        me._rules = {
            required: function(val) { //必填 true:表示有值, false:表示空或无值
                return !!(val && !/^(?:\s|\u3000)+$/.test(val));
            },
            remote: function(xhr, val) {
                val === 'true' && (val = true);
                return !!(val && val === true);
            },
            email: /^[\w!#\$%'\*\+\-\/=\?\^`{}\|~]+([.][\w!#\$%'\*\+\-\/=\?\^`{}\|~]+)*@([a-z0-9\-]{1,20}[.])+[a-z0-9\-]{1,10}([.][a-z]{2})?$/i,
            number: /^(?:[1-9]\d+|\d)(?:\.\d+)?$/,
            maxlength: function(val, opt) {
                return val.length <= opt;
            },
            minlength: function(val, opt) {
                return val.length >= opt;
            },
            rangelength: function(val, opt) {
                return val.length >= opt[0] && val.length <= opt[1];
            },
            equal: function(val, opt) {
                return val === ($.isFunction(opt) ? opt() : opt);
            },
            telephone: /^(0[0-9]{2,3}\-)?([1-9][0-9]{6,7})+(\-[0-9]{1,4})?$|(400|800)([0-9\\-]{7,10})|(^(13[0-9]|14[0-9]|15[0-9]|18[0-9])\d{8}$)/,
            fixedtelephone: /^((0[0-9]{2,3}\-){1}([1-9][0-9]{6,7})+(\-[0-9]{1,4})?|(400|800)([0-9\\-]{7,10}))$/,
            cellphone: /^(13[0-9]|14[0-9]|15[0-9]|18[0-9])\d{8}$/,
            maxlengthGB: function(val, opt) {
                return val.replace(/[\u4E00-\u9FA5\u3000，。；！？]/g, "**").length <= opt;
            },
            minlengthGB: function(val, opt) {
                return val.replace(/[\u4E00-\u9FA5\u3000，。；！？]/g, "**").length >= opt;
            },
            realname: /^[A-Za-z\s\uff21-\uff3a\uff41-\uff5a\u4e00-\u9fa5]+$/,
            username: /^[A-Za-z]+[A-Za-z0-9\-_]*$/,
            sspname: /^[A-Za-z0-9\-_\u4e00-\u9fa5]+$/,
            idcard: /^\d{14}(\d{1}|\d{4}|(\d{3}[xX]))$/,
            zipcode: /^\d\d{5}$/,
            intnumber: /^\d+$/,
            floatnumber: /^(\d*\.)?\d+$/,
            negfloatnumber:/^[+-]?(?:[1-9]\d+|\d)(?:\.\d+)?$/,
            nonumber: /^\D+$/,
            password: /^[\s\w-`=\\\[\];',.\/~!@#$%^&*()_+|{}:"<>?]+$/,
            maxval: function(val, opt) {
                return parseFloat(val) <= opt;
            },
            minval: function(val, opt) {
                return parseFloat(val) >= opt;
            },
            url: /^(https?):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i,
            httpurl: /^(http):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i,
            macrourl: /^(http):\/\/(((([a-z]|\d|-|\.|_|~|[\u007B-\u007D\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u007B-\u007D\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u007B-\u007D\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u007B-\u007D\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u007B-\u007D\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u007B-\u007D\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|_|~|[\u007B-\u007D\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u007B-\u007D\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u007B-\u007D\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u007B-\u007D\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u007B-\u007D\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u007B-\u007D\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i,
            macroSpecialUrl: /(http):\/\/(((([a-z]|\d|-|\.|_|~|[\u007B-\u007D\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u007B-\u007D\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u007B-\u007D\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u007B-\u007D\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u007B-\u007D\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u007B-\u007D\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|_|~|[\u007B-\u007D\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u007B-\u007D\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u007B-\u007D\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u007B-\u007D\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u007B-\u007D\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u007B-\u007D\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i,
            simpleUrl: /^((https|http|ftp|rtsp|mms)?:\/\/)[^\s]+/
        };
    }).extend({
        /**
         * 根据规则名称取得对应的规则，参数可选，没有参数则返回所有规则的对象
         * @param {String} name 已知的规则名称
         * @private
         */
        _getRule: function(name) {
            var me = this;
            return $.isString(name) ? me._rules[name] : me._rules;
        },

        /**
         * 用一个验证方法对一个已经存在的值进行验证，并将结果返回到回调中。说明：如果是一个remote验证，则是一个ajax验证，请让服务器返回true或是false来表示验证结果
         * @param {String} name 验证方法的名称，如：required,email等
         * @param {String} field 验证域的名称
         * @param {String} val 需要被验证的字符串值，如果是remote该参数可以忽视
         * @param {Function} callback 验证结束的回调，第一参数为验证结果
         * @param {Object} options 表示验证需要的参数，如当验证类型是maxlength时，需要options是{param:10}
         */
        match: function(name, field, val, callback, options) {
            var me = this,
                rule = me._getRule(name),
                param = options && options.param,
                requestData = {};
            if ('remote' === name.toLowerCase()) {
                $.isString(param) && (param = {
                    url: param
                });
                param = VAM.object.extend({}, param);
                param.data && $.isFunction(param.data) && (param.data = param.data(val));
                param.onsuccess = param.onfailure = function(responseText, status, xhr) {
                    responseText = $.trim(responseText);
                    responseText === 'true' && (responseText = true);
                    responseText === 'false' && (responseText = false);

                    callback(rule(xhr, responseText));
                };
                //data只接受字符串,函数
                if ($.isFunction(param.data)) {
                    requestData = param.data();
                } else if ($.isString(param.data)) {
                    requestData = param.data;
                } else {
                    requestData[field] = val;
                }
                (param.method === 'post' ? $.post : $.get)(param.url, requestData, param.onsuccess);
            } else {
                callback($.isFunction(rule) ? rule(val, param) : rule.test(val));
            }
        },

        /**
         * 增加一条验证规则
         * @param {String} name 验证规则的名称
         * @param {Function|RegExp} handler 执行验证的函数或是正则表达式，如果是函数，需要返回一个boolean
         */
        addRule: function(name, handler) {
            this._rules[name] = handler;
        }
    });

	})(jQuery, jQuery, window);
});